iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Rust

大家一起跟Rust當好朋友吧!系列 第 3

Day 3: 函式與流程控制:讓程式有邏輯、有組織

  • 分享至 

  • xImage
  •  

嗨嗨!大家好!歡迎來到 Rust 三十天挑戰的第三天!

經過前兩天的基礎洗禮,相信大家對 Rust 的變數和型別系統已經有了初步的認識。今天我們要來學習如何讓程式更有組織性和邏輯性—那就是函式(Functions)和流程控制(Control Flow)!

老實說,剛開始學 Rust 的函式時,我最驚訝的是它對「表達式」和「陳述句」的區分非常嚴格。這在其他語言中可能不是什麼大事,但在 Rust 中卻是非常重要的概念。比如說,if 在 Rust 中不只是條件判斷,它還可以回傳值!這種設計讓程式碼變得更簡潔,但一開始可能會讓人有點不習慣。

不過別擔心,等你理解了這個概念,你會發現 Rust 的表達式系統其實非常優雅和強大!

函式:程式碼的組織單位

基本函式語法

在 Rust 中,我們使用 fn 關鍵字來定義函式:

fn main() {
    println!("Hello from main!");
    greet();
    say_hello("小明");
}

fn greet() {
    println!("哈囉!歡迎來到 Rust 的世界!");
}

fn say_hello(name: &str) {
    println!("你好,{}!", name);
}

函式參數

Rust 的函式參數必須明確指定型別:

fn add_numbers(x: i32, y: i32) {
    let result = x + y;
    println!("{} + {} = {}", x, y, result);
}

fn calculate_area(width: f64, height: f64) {
    let area = width * height;
    println!("長方形面積:{:.2} 平方公分", area);
}

fn main() {
    add_numbers(5, 3);
    calculate_area(10.5, 8.2);
}

函式回傳值

這裡來了!Rust 中函式回傳值的語法可能會讓你覺得有點特別:

fn add(x: i32, y: i32) -> i32 {
    x + y  // 注意:沒有分號!
}

fn multiply(x: i32, y: i32) -> i32 {
    return x * y;  // 也可以明確使用 return
}

fn get_lucky_number() -> i32 {
    42  // 最後一個表達式會被當作回傳值
}

fn main() {
    let sum = add(5, 3);
    let product = multiply(4, 6);
    let lucky = get_lucky_number();
    
    println!("加法:{},乘法:{},幸運數字:{}", sum, product, lucky);
}

重要概念:在 Rust 中,函式的最後一個表達式(沒有分號的那行)會自動成為回傳值

表達式 vs 陳述句

這是理解 Rust 的重要概念:

  • 陳述句(Statements):執行動作但不回傳值,以分號結尾
  • 表達式(Expressions):計算出一個值,沒有分號
fn main() {
    let x = 5;  // 這是陳述句
    
    let y = {
        let inner = 3;
        inner + 1  // 這是表達式,沒有分號
    };  // 整個區塊是表達式
    
    println!("x = {}, y = {}", x, y);  // y 的值是 4
}

流程控制:讓程式做決策

if 表達式

沒錯,在 Rust 中 if 是表達式,可以回傳值!

fn main() {
    let number = 6;
    
    // 傳統的 if 用法
    if number % 4 == 0 {
        println!("數字可以被 4 整除");
    } else if number % 3 == 0 {
        println!("數字可以被 3 整除");
    } else if number % 2 == 0 {
        println!("數字可以被 2 整除");
    } else {
        println!("數字不能被 4、3 或 2 整除");
    }
    
    // if 作為表達式回傳值
    let message = if number % 2 == 0 {
        "偶數"
    } else {
        "奇數"
    };
    
    println!("{} 是 {}", number, message);
}

迴圈:loopwhilefor

1. loop:無限迴圈

fn main() {
    let mut counter = 0;
    
    let result = loop {
        counter += 1;
        
        if counter == 10 {
            break counter * 2;  // loop 也可以回傳值!
        }
    };
    
    println!("結果:{}", result);  // 輸出:結果:20
}

2. while:條件迴圈

fn main() {
    let mut number = 3;
    
    while number != 0 {
        println!("{}!", number);
        number -= 1;
    }
    
    println!("發射!");
}

3. for:迭代迴圈

fn main() {
    // 迭代陣列
    let animals = ["狗", "貓", "兔子", "鳥"];
    
    for animal in animals {
        println!("我喜歡{}", animal);
    }
    
    // 迭代範圍
    println!("\n倒數:");
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("發射!🚀");
    
    // 使用索引
    println!("\n帶索引的迴圈:");
    for (index, animal) in animals.iter().enumerate() {
        println!("第 {} 個動物是 {}", index + 1, animal);
    }
}

巢狀迴圈與標籤

當你有巢狀迴圈時,可以使用標籤來控制要中斷哪一層:

fn main() {
    'outer: loop {
        println!("進入外層迴圈");
        
        loop {
            println!("進入內層迴圈");
            break 'outer;  // 直接中斷外層迴圈
        }
        
        println!("這行永遠不會執行");
    }
    
    println!("外層迴圈結束");
}

實戰練習:改進我們的小程式

讓我們用今天學到的知識來建立一個更有組織的程式,完成前兩天的小挑戰:這個程式展示了今天學到的許多重要概念:

程式亮點解析

1. 函式的組織

  • 每個函式都有明確的職責
  • 函式名稱清楚表達其功能
  • 適當地使用參數和回傳值

2. 流程控制的應用

  • loop 來處理輸入驗證
  • for 迴圈遍歷陣列
  • match 表達式處理不同情況
  • if/else 表達式回傳值

3. 表達式的妙用

  • match 根據偶數數量回傳不同訊息
  • if/else 鏈來分類數字
  • 函式最後的表達式作為回傳值

進階技巧:match 表達式

雖然我們還沒正式介紹 match,但它實在太好用了,讓我簡單展示一下:

fn describe_number(n: i32) -> &'static str {
    match n {
        0 => "零",
        1..=5 => "小數字",
        6..=10 => "中等數字",
        11..=100 => "大數字",
        _ => "超大數字",
    }
}

fn get_grade(score: u8) -> char {
    match score {
        90..=100 => 'A',
        80..=89 => 'B', 
        70..=79 => 'C',
        60..=69 => 'D',
        _ => 'F',
    }
}

fn main() {
    println!("7 是 {}", describe_number(7));
    println!("95 分的等第是 {}", get_grade(95));
}

💡 補充說明:在此稍微小說明一下,有關於 &'static str 這個使用方法其實是有那麼一點點點小超綱XD
在之後會有一天專門說明他概念的!大家不用擔心!!

今天的收穫

今天我們學到了:

函式

  • 使用 fn 定義函式
  • 參數必須明確指定型別
  • 最後一個表達式(無分號)作為回傳值
  • 可以明確使用 return

流程控制

  • if/else 是表達式,可以回傳值
  • loopwhilefor 三種迴圈
  • breakcontinue 控制迴圈流程
  • 迴圈標籤處理巢狀迴圈

表達式 vs 陳述句

  • 表達式計算出值,沒有分號
  • 陳述句執行動作,以分號結尾
  • 區塊也是表達式

實用技巧

  • 錯誤處理的基本模式
  • 函式的職責分離
  • 程式碼組織的最佳實務

明天我們將進入 Rust 最核心也最獨特的概念—所有權系統。這是 Rust 能夠同時保證記憶體安全和高效能的秘密武器。雖然一開始可能會覺得有點抽象,但它絕對是值得深入理解的概念!

今天的小挑戰

試著建立一個簡單的計算機程式,要求:

  1. 建立一個選單讓使用者選擇運算(加、減、乘、除)
  2. 讀取兩個數字
  3. 根據選擇執行對應的運算
  4. 顯示結果
  5. 詢問是否繼續

提示:

  • 使用函式來組織程式碼
  • 善用 match 表達式處理選單選擇
  • 記得處理除以零的情況!

如果遇到任何問題,歡迎在留言區討論。函式和流程控制是程式設計的基礎,掌握它們會讓你在後續的學習中更加順利!

我們明天見!


上一篇
Day 2: 變數、資料型別與常數:強型別的第一次接觸
下一篇
Day 4: 所有權 (Ownership):Rust 最核心的概念!
系列文
大家一起跟Rust當好朋友吧!20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言